package org.offsync.old.async

import java.nio.channels.SocketChannel
import java.nio.ByteBuffer
import org.offsync.rich._
import org.offsync.util.DisposableBase
import org.offsync.util.Window
import java.net.SocketAddress

class AsyncSocket(val channel: SocketChannel) extends DisposableBase {
  def read(
      asyncService: AsyncService,
      length: Int)(
          callback: AsyncResult[Option[Array[Byte]]] => AsyncReturn): AsyncReturn = {
    // Register the server socket channel, indicating an interest in 
    // accepting new connections
    channel.onReadable(asyncService) { () =>
      val byteBuffer = ByteBuffer.allocate(length)
      val bytesRead = channel.read(byteBuffer)
      bytesRead match {
        case -1 => {
          callback(AsyncResult(None))
        }
        case _ => {
          callback(AsyncResult(Some(byteBuffer.array())))
        }
      }
    }
    
    AsyncReturn
  }
  
  def write(
      asyncService: AsyncService,
      array: Array[Byte])(
          callback: AsyncResult[Unit] => AsyncReturn): AsyncReturn = {
    write(asyncService, Window to array)(callback)
  }
  
  def write(
      asyncService: AsyncService,
      window: Window[Byte])(
          callback: AsyncResult[Unit] => AsyncReturn): AsyncReturn = {
    // Register the server socket channel, indicating an interest in 
    // accepting new connections
    channel.onWritable(asyncService) { () =>
      val byteBuffer = window.toByteBuffer()
      val socketChannel = channel.write(byteBuffer)
      callback(AsyncResult{})
    }
    
    AsyncReturn
  }
  
  protected override def onDispose(): Unit = {
    try channel.close() catch { case e => }
    
    super.onDispose()
  }
}

object AsyncSocket {
  def open(socketAddress: SocketAddress) = {
    val socketChannel = SocketChannel.open(socketAddress)
    socketChannel.configureBlocking(false)
    new AsyncSocket(socketChannel)
  }
}
